package mspbots.tsheets.client.core.times;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.extern.log4j.Log4j2;
import mspbots.tsheets.client.core.AbstractToolsUtil;
import mspbots.tsheets.client.core.BaseSyncService;
import mspbots.tsheets.client.core.TokenState;
import mspbots.tsheets.common.*;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.Map;


/**
 * @author AlexBob
 */
@Log4j2
@Service
public class TimesServiceImpl extends AbstractToolsUtil implements BaseSyncService {

    @Override
    public Mono<Void> syncFast(TokenState tokenState) {
        ResultSync resultSync = ResultSync.withDefault(tokenState.getTenantId(), "tsheetsS-SYNC");
        return this.filterCacheGet(tokenState)
                .doOnNext(resultNode -> this.sendEntity(RabbitKeys.TIME_SYNC_QUEUE_KEY, ResultMsg.builder()
                        .requestId(resultSync.getRequestId()).id(resultNode.get("id").longValue())
                        .action("none").entity(resultNode).tenantId(tokenState.getTenantId())
                        .syncDate(LocalDateTime.now()).build()))
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .then();
    }

    private Flux<JsonNode> filterCacheGet(TokenState tokenState) {
        String anchorTimeKey = RedisKeys.TIME_SHEETS_ANCHOR_REDIS_KEY_PREFIX + tokenState.getTenantId();
        return this.readAnchorTime(anchorTimeKey)
                .map(time -> QueryParams.withDefault().setModifiedSince(time))
                .flatMapMany(this::get)
                .subscriberContext(ctx -> ctx.put("token", tokenState))
                .doOnNext(jsonNode -> this.recordAnchorTime(anchorTimeKey, jsonNode.get("last_modified").textValue()));
    }

    private Flux<JsonNode> get(QueryParams queryParams) {
        queryParams.set("on_the_clock", "both");
        queryParams.set("supplemental_data", "no");
        return super.sheetsClient.fetch("/timesheets", queryParams)
                .map(usersNode -> this.objectMapper.convertValue(usersNode.get("timesheets"), new TypeReference<Map<String, JsonNode>>() {
                }))
                .flatMap(mapUser -> Flux.fromStream(mapUser.values().parallelStream()));
    }

}
